home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / awksrc.zip / FIELD.C < prev    next >
C/C++ Source or Header  |  1993-09-27  |  17KB  |  666 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include <stdlib.h>
  27. #include "awk.h"
  28.  
  29. static int (*parse_field) P((int, char **, int, char *,
  30.                  Regexp *, void (*)(), NODE *));
  31. static void rebuild_record P((void));
  32. static int re_parse_field P((int, char **, int, char *,
  33.                  Regexp *, void (*)(), NODE *));
  34. static int def_parse_field P((int, char **, int, char *,
  35.                   Regexp *, void (*)(), NODE *));
  36. static int sc_parse_field P((int, char **, int, char *,
  37.                  Regexp *, void (*)(), NODE *));
  38. static int fw_parse_field P((int, char **, int, char *,
  39.                  Regexp *, void (*)(), NODE *));
  40. static void set_element P((int, char *, int, NODE *));
  41. static void grow_fields_arr P((int num));
  42. static void set_field P((int num, char *str, int len, NODE *dummy));
  43.  
  44.  
  45. static Regexp *FS_regexp = NULL;
  46. static char *parse_extent;    /* marks where to restart parse of record */
  47. static int parse_high_water=0;    /* field number that we have parsed so far */
  48. static int nf_high_water = 0;    /* size of fields_arr */
  49. static int resave_fs;
  50. static NODE *save_FS;
  51. static char *save_fs;        /* save current value of FS when line is read,
  52.                  * to be used in deferred parsing
  53.                  */
  54.  
  55. NODE **fields_arr;        /* array of pointers to the field nodes */
  56. int field0_valid;        /* $(>0) has not been changed yet */
  57. int default_FS;
  58. static NODE **nodes;        /* permanent repository of field nodes */
  59. static int *FIELDWIDTHS = NULL;
  60.  
  61. void
  62. init_fields()
  63. {
  64.     NODE *n;
  65.  
  66.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  67.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  68.     getnode(n);
  69.     *n = *Nnull_string;
  70.     fields_arr[0] = nodes[0] = n;
  71.     parse_extent = fields_arr[0]->stptr;
  72.     save_FS = dupnode(FS_node->var_value);
  73.     save_fs = save_FS->stptr;
  74.     field0_valid = 1;
  75. }
  76.  
  77.  
  78. static void
  79. grow_fields_arr(num)
  80. int num;
  81. {
  82.     register int t;
  83.     register NODE *n;
  84.  
  85.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  86.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
  87.     for (t = nf_high_water+1; t <= num; t++) {
  88.         getnode(n);
  89.         *n = *Nnull_string;
  90.         fields_arr[t] = nodes[t] = n;
  91.     }
  92.     nf_high_water = num;
  93. }
  94.  
  95. /*ARGSUSED*/
  96. static void
  97. set_field(num, str, len, dummy)
  98. int num;
  99. char *str;
  100. int len;
  101. NODE *dummy;    /* not used -- just to make interface same as set_element */
  102. {
  103.     register NODE *n;
  104.  
  105.     if (num > nf_high_water)
  106.         grow_fields_arr(num);
  107.     n = nodes[num];
  108.     n->stptr = str;
  109.     n->stlen = len;
  110.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  111.     fields_arr[num] = n;
  112. }
  113.  
  114. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  115. static void
  116. rebuild_record()
  117. {
  118.     register int tlen;
  119.     register NODE *tmp;
  120.     NODE *ofs;
  121.     char *ops;
  122.     register char *cops;
  123.     register NODE **ptr;
  124.     register int ofslen;
  125.  
  126.     tlen = 0;
  127.     ofs = force_string(OFS_node->var_value);
  128.     ofslen = ofs->stlen;
  129.     ptr = &fields_arr[NF];
  130.     while (ptr > &fields_arr[0]) {
  131.         tmp = force_string(*ptr);
  132.         tlen += tmp->stlen;
  133.         ptr--;
  134.     }
  135.     tlen += (NF - 1) * ofslen;
  136.     if (tlen < 0)
  137.         tlen = 0;
  138.     emalloc(ops, char *, tlen + 2, "fix_fields");
  139.     cops = ops;
  140.     ops[0] = '\0';
  141.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  142.         tmp = *ptr;
  143.         if (tmp->stlen == 1)
  144.             *cops++ = tmp->stptr[0];
  145.         else if (tmp->stlen != 0) {
  146.             memcpy(cops, tmp->stptr, tmp->stlen);
  147.             cops += tmp->stlen;
  148.         }
  149.         if (ptr != &fields_arr[NF]) {
  150.             if (ofslen == 1)
  151.                 *cops++ = ofs->stptr[0];
  152.             else if (ofslen != 0) {
  153.                 memcpy(cops, ofs->stptr, ofslen);
  154.                 cops += ofslen;
  155.             }
  156.         }
  157.     }
  158.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  159.     unref(fields_arr[0]);
  160.     fields_arr[0] = tmp;
  161.     field0_valid = 1;
  162. }
  163.  
  164. /*
  165.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  166.  * or to NF.  At that point, parse only as much as necessary.
  167.  */
  168. void
  169. set_record(buf, cnt, freeold)
  170. char *buf;
  171. int cnt;
  172. int freeold;
  173. {
  174.     register int i;
  175.  
  176.     NF = -1;
  177.     for (i = 1; i <= parse_high_water; i++) {
  178.         unref(fields_arr[i]);
  179.     }
  180.     parse_high_water = 0;
  181.     if (freeold) {
  182.         unref(fields_arr[0]);
  183.         if (resave_fs) {
  184.             resave_fs = 0;
  185.             unref(save_FS);
  186.             save_FS = dupnode(FS_node->var_value);
  187.             save_fs = save_FS->stptr;
  188.         }
  189.         nodes[0]->stptr = buf;
  190.         nodes[0]->stlen = cnt;
  191.         nodes[0]->stref = 1;
  192.         nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM);
  193.         fields_arr[0] = nodes[0];
  194.     }
  195.     fields_arr[0]->flags |= MAYBE_NUM;
  196.     field0_valid = 1;
  197. }
  198.  
  199. void
  200. reset_record()
  201. {
  202.     (void) force_string(fields_arr[0]);
  203.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
  204. }
  205.  
  206. void
  207. set_NF()
  208. {
  209.     register int i;
  210.  
  211.     NF = (int) force_number(NF_node->var_value);
  212.     if (NF > nf_high_water)
  213.         grow_fields_arr(NF);
  214.     for (i = parse_high_water + 1; i <= NF; i++) {
  215.         unref(fields_arr[i]);
  216.         fields_arr[i] = Nnull_string;
  217.     }
  218.     field0_valid = 0;
  219. }
  220.  
  221. /*
  222.  * this is called both from get_field() and from do_split()
  223.  * via (*parse_field)().  This variation is for when FS is a regular
  224.  * expression -- either user-defined or because RS=="" and FS==" "
  225.  */
  226. static int
  227. re_parse_field(up_to, buf, len, fs, rp, set, n)
  228. int up_to;    /* parse only up to this field number */
  229. char **buf;    /* on input: string to parse; on output: point to start next */
  230. int len;
  231. register char *fs;
  232. Regexp *rp;
  233. void (*set) ();    /* routine to set the value of the parsed field */
  234. NODE *n;
  235. {
  236.     register char *scan = *buf;
  237.     register int nf = parse_high_water;
  238.     register char *field;
  239.     register char *end = scan + len;
  240.  
  241.     if (up_to == HUGE)
  242.         nf = 0;
  243.     if (len == 0)
  244.         return nf;
  245.  
  246.     if (*RS == 0 && default_FS)
  247.         while (scan < end && isspace(*scan))
  248.             scan++;
  249.     field = scan;
  250.     while (scan < end
  251.            && research(rp, scan, 0, (int)(end - scan), 1) != -1
  252.            && nf < up_to) {
  253.         if (REEND(rp, scan) == RESTART(rp, scan)) {    /* null match */
  254.             scan++;
  255.             if (scan == end) {
  256.                 (*set)(++nf, field, scan - field, n);
  257.                 up_to = nf;
  258.                 break;
  259.             }
  260.             continue;
  261.         }
  262.         (*set)(++nf, field, RESTART(rp, scan), n);
  263.         scan += REEND(rp, scan);
  264.         field = scan;
  265.         if (scan == end)    /* FS at end of record */
  266.             (*set)(++nf, field, 0, n);
  267.     }
  268.     if (nf != up_to && scan < end) {
  269.         (*set)(++nf, scan, (int)(end - scan), n);
  270.         scan = end;
  271.     }
  272.     *buf = scan;
  273.     return (nf);
  274. }
  275.  
  276. /*
  277.  * this is called both from get_field() and from do_split()
  278.  * via (*parse_field)().  This variation is for when FS is a single space
  279.  * character.
  280.  */
  281. static int
  282. def_parse_field(up_to, buf, len, fs, rp, set, n)
  283. int up_to;    /* parse only up to this field number */
  284. char **buf;    /* on input: string to parse; on output: point to start next */
  285. int len;
  286. register char *fs;
  287. Regexp *rp;
  288. void (*set) ();    /* routine to set the value of the parsed field */
  289. NODE *n;
  290. {
  291.     register char *scan = *buf;
  292.     register int nf = parse_high_water;
  293.     register char *field;
  294.     register char *end = scan + len;
  295.     char sav;
  296.  
  297.     if (up_to == HUGE)
  298.         nf = 0;
  299.     if (len == 0)
  300.         return nf;
  301.  
  302.     /* before doing anything save the char at *end */
  303.     sav = *end;
  304.     /* because it will be destroyed now: */
  305.  
  306.     *end = ' ';    /* sentinel character */
  307.     for (; nf < up_to; scan++) {
  308.         /*
  309.          * special case:  fs is single space, strip leading whitespace 
  310.          */
  311.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  312.             scan++;
  313.         if (scan >= end)
  314.             break;
  315.         field = scan;
  316.         while (*scan != ' ' && *scan != '\t')
  317.             scan++;
  318.         (*set)(++nf, field, (int)(scan - field), n);
  319.         if (scan == end)
  320.             break;
  321.     }
  322.  
  323.     /* everything done, restore original char at *end */
  324.     *end = sav;
  325.  
  326.     *buf = scan;
  327.     return nf;
  328. }
  329.  
  330. /*
  331.  * this is called both from get_field() and from do_split()
  332.  * via (*parse_field)().  This variation is for when FS is a single character
  333.  * other than space.
  334.  */
  335. static int
  336. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  337. int up_to;    /* parse only up to this field number */
  338. char **buf;    /* on input: string to parse; on output: point to start next */
  339. int len;
  340. register char *fs;
  341. Regexp *rp;
  342. void (*set) ();    /* routine to set the value of the parsed field */
  343. NODE *n;
  344. {
  345.     register char *scan = *buf;
  346.     register char fschar = *fs;
  347.     register int nf = parse_high_water;
  348.     register char *field;
  349.     register char *end = scan + len;
  350.     char sav;
  351.  
  352.     if (up_to == HUGE)
  353.         nf = 0;
  354.     if (len == 0)
  355.         return nf;
  356.  
  357.     /* before doing anything save the char at *end */
  358.     sav = *end;
  359.     /* because it will be destroyed now: */
  360.  
  361.     *end = fschar;    /* sentinel character */
  362.     for (; nf < up_to; scan++) {
  363.         field = scan;
  364.         while (*scan++ != fschar)
  365.             ;
  366.         scan--;
  367.         (*set)(++nf, field, (int)(scan - field), n);
  368.         if (scan == end)
  369.             break;
  370.     }
  371.  
  372.     /* everything done, restore original char at *end */
  373.     *end = sav;
  374.  
  375.     *buf = scan;
  376.     return nf;
  377. }
  378.  
  379. /*
  380.  * this is called both from get_field() and from do_split()
  381.  * via (*pase_field)().  This variation is for when FS is a single character
  382.  * other than space.
  383.  */
  384. static int
  385. fw_parse_field(up_to, buf, len, fs, rp, set, n)
  386. int up_to;    /* parse only up to this field number */
  387. char **buf;    /* on input: string to parse; on output: point to start next */
  388. int len;
  389. register char *fs;
  390. Regexp *rp;
  391. void (*set) ();    /* routine to set the value of the parsed field */
  392. NODE *n;
  393. {
  394.     register char *scan = *buf;
  395.     register int nf = parse_high_water;
  396.     register char *end = scan + len;
  397.  
  398.     if (up_to == HUGE)
  399.         nf = 0;
  400.     if (len == 0)
  401.         return nf;
  402.     for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) {
  403.         if (len > end - scan)
  404.             len = end - scan;
  405.         (*set)(++nf, scan, len, n);
  406.         scan += len;
  407.     }
  408.     if (len == -1)
  409.         *buf = end;
  410.     else
  411.         *buf = scan;
  412.     return nf;
  413. }
  414.  
  415. NODE **
  416. get_field(requested, assign)
  417. register int requested;
  418. Func_ptr *assign;    /* this field is on the LHS of an assign */
  419. {
  420.     /*
  421.      * if requesting whole line but some other field has been altered,
  422.      * then the whole line must be rebuilt
  423.      */
  424.     if (requested == 0) {
  425.         if (!field0_valid) {
  426.             /* first, parse remainder of input record */
  427.             if (NF == -1) {
  428.                 NF = (*parse_field)(HUGE-1, &parse_extent,
  429.                         fields_arr[0]->stlen -
  430.                     (parse_extent - fields_arr[0]->stptr),
  431.                         save_fs, FS_regexp, set_field,
  432.                     (NODE *)NULL);
  433.                 parse_high_water = NF;
  434.             }
  435.             rebuild_record();
  436.         }
  437.         if (assign)
  438.             *assign = reset_record;
  439.         return &fields_arr[0];
  440.     }
  441.  
  442.     /* assert(requested > 0); */
  443.  
  444.     if (assign)
  445.         field0_valid = 0;        /* $0 needs reconstruction */
  446.  
  447.     if (requested <= parse_high_water)    /* already parsed this field */
  448.         return &fields_arr[requested];
  449.  
  450.     if (NF == -1) {    /* have not yet parsed to end of record */
  451.         /*
  452.          * parse up to requested fields, calling set_field() for each,
  453.          * saving in parse_extent the point where the parse left off
  454.          */
  455.         if (parse_high_water == 0)    /* starting at the beginning */
  456.             parse_extent = fields_arr[0]->stptr;
  457.         parse_high_water = (*parse_field)(requested, &parse_extent,
  458.              fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  459.              save_fs, FS_regexp, set_field, (NODE *)NULL);
  460.  
  461.         /*
  462.          * if we reached the end of the record, set NF to the number of 
  463.          * fields so far.  Note that requested might actually refer to
  464.          * a field that is beyond the end of the record, but we won't
  465.          * set NF to that value at this point, since this is only a
  466.          * reference to the field and NF only gets set if the field
  467.          * is assigned to -- this case is handled below
  468.          */
  469.         if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen)
  470.             NF = parse_high_water;
  471.         if (requested == HUGE-1)    /* HUGE-1 means set NF */
  472.             requested = parse_high_water;
  473.     }
  474.     if (parse_high_water < requested) { /* requested beyond end of record */
  475.         if (assign) {    /* expand record */
  476.             register int i;
  477.  
  478.             if (requested > nf_high_water)
  479.                 grow_fields_arr(requested);
  480.  
  481.             /* fill in fields that don't exist */
  482.             for (i = parse_high_water + 1; i <= requested; i++)
  483.                 fields_arr[i] = Nnull_string;
  484.  
  485.             NF = requested;
  486.             parse_high_water = requested;
  487.         } else
  488.             return &Nnull_string;
  489.     }
  490.  
  491.     return &fields_arr[requested];
  492. }
  493.  
  494. static void
  495. set_element(num, s, len, n)
  496. int num;
  497. char *s;
  498. int len;
  499. NODE *n;
  500. {
  501.     register NODE *it;
  502.  
  503.     it = make_string(s, len);
  504.     it->flags |= MAYBE_NUM;
  505.     *assoc_lookup(n, tmp_number((AWKNUM) (num))) = it;
  506. }
  507.  
  508. NODE *
  509. do_split(tree)
  510. NODE *tree;
  511. {
  512.     NODE *t1, *t2, *t3, *tmp;
  513.     register char *splitc = "";
  514.     char *s;
  515.     int (*parseit)P((int, char **, int, char *,
  516.              Regexp *, void (*)(), NODE *));
  517.     Regexp *rp = NULL;
  518.  
  519.     t1 = tree_eval(tree->lnode);
  520.     t2 = tree->rnode->lnode;
  521.     t3 = tree->rnode->rnode->lnode;
  522.  
  523.     (void) force_string(t1);
  524.  
  525.     if (t2->type == Node_param_list)
  526.         t2 = stack_ptr[t2->param_cnt];
  527.     if (t2->type != Node_var && t2->type != Node_var_array)
  528.         fatal("second argument of split is not a variable");
  529.     assoc_clear(t2);
  530.  
  531.     if (t3->re_flags & FS_DFLT) {
  532.         parseit = parse_field;
  533.         splitc = FS;
  534.         rp = FS_regexp;
  535.     } else {
  536.         tmp = force_string(tree_eval(t3->re_exp));
  537.         if (tmp->stlen == 1) {
  538.             if (tmp->stptr[0] == ' ') {
  539.                 parseit = def_parse_field;
  540.             } else {
  541.                 parseit = sc_parse_field;
  542.                 splitc = tmp->stptr;
  543.             }
  544.         } else {
  545.             parseit = re_parse_field;
  546.             rp = re_update(t3);
  547.         }
  548.         free_temp(tmp);
  549.     }
  550.  
  551.     s = t1->stptr;
  552.     tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen,
  553.                          splitc, rp, set_element, t2));
  554.     free_temp(t1);
  555.     return tmp;
  556. }
  557.  
  558. void
  559. set_FS()
  560. {
  561.     register NODE *tmp;
  562.     static char buf[10];
  563.  
  564.     default_FS = 0;
  565.     if (FS_regexp) {
  566.         refree(FS_regexp);
  567.         FS_regexp = NULL;
  568.     }
  569.     parse_field = def_parse_field;
  570.     tmp = force_string(FS_node->var_value);
  571.     FS = tmp->stptr;
  572.     if (*RS == 0) {
  573.         parse_field = re_parse_field;
  574.         FS = buf;
  575.         if (tmp->stlen == 1) {
  576.             if (tmp->stptr[0] == ' ') {
  577.                 (void) strcpy(buf, "[     \n]+");
  578.                 default_FS = 1;
  579.             } else if (tmp->stptr[0] != '\n') {
  580.                 if (IGNORECASE == 0)
  581.                     sprintf(buf, "[%c\n]", tmp->stptr[0]);
  582.                 else {
  583.                     char c = tmp->stptr[0];
  584.                         
  585.                     sprintf(buf, "[%c%c\n]",
  586.                       c, islower(c) ? toupper(c) : isupper(c) ? tolower(c) : c );
  587.                 }
  588.             } else {
  589.                 parse_field = sc_parse_field;
  590.                 FS = tmp->stptr;
  591.             }
  592.         } else if (tmp->stlen == 0) {
  593.             buf[0] = '\n';
  594.             buf[1] = '\0';
  595.             parse_field = sc_parse_field;
  596.         } else
  597.             FS = tmp->stptr;
  598.     } else {
  599.         if (tmp->stlen > 1)
  600.             parse_field = re_parse_field;
  601.         else if (*FS == ' ' && tmp->stlen == 1)
  602.             default_FS = 1;
  603.         else if (*FS != ' ' && tmp->stlen == 1) {
  604.             if (IGNORECASE == 0)
  605.                 parse_field = sc_parse_field;
  606.             else {
  607.                 char c = *FS;
  608.                     
  609.                 sprintf(buf, "[%c%c]",
  610.                   c, islower(c) ? toupper(c) : isupper(c) ? tolower(c) : c );
  611.                   parse_field = re_parse_field;
  612.             }
  613.         }
  614.     }
  615.     if (parse_field == re_parse_field) {
  616.         tmp = tmp_string(FS, strlen(FS));
  617.         FS_regexp = make_regexp(tmp, IGNORECASE, 1);
  618.         free_temp(tmp);
  619.     } else
  620.         FS_regexp = NULL;
  621.     resave_fs = 1;
  622. }
  623.  
  624. void
  625. set_RS()
  626. {
  627.     (void) force_string(RS_node->var_value);
  628.     RS = RS_node->var_value->stptr;
  629.     set_FS();
  630. }
  631.  
  632. void
  633. set_FIELDWIDTHS()
  634. {
  635.     register char *scan;
  636.     char *end;
  637.     register int i;
  638.     static int fw_alloc = 1;
  639.     static int warned = 0;
  640.  
  641.     if (do_lint && ! warned) {
  642.         warned = 1;
  643.         warning("use of FIELDWIDTHS is a gawk extension");
  644.     }
  645.     if (strict)    /* quick and dirty, does the trick */
  646.         return;
  647.  
  648.     parse_field = fw_parse_field;
  649.     scan = force_string(FIELDWIDTHS_node->var_value)->stptr;
  650.     end = scan + 1;
  651.     if (FIELDWIDTHS == NULL)
  652.         emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  653.     FIELDWIDTHS[0] = 0;
  654.     for (i = 1; ; i++) {
  655.         if (i >= fw_alloc) {
  656.             fw_alloc *= 2;
  657.             erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS");
  658.         }
  659.         FIELDWIDTHS[i] = (int) strtod(scan, &end);
  660.         if (end == scan)
  661.             break;
  662.         scan = end;
  663.     }
  664.     FIELDWIDTHS[i] = -1;
  665. }
  666.